package com.ruoyi.framework.aspectj;

import com.ruoyi.common.annotation.AddDataScope;
import com.ruoyi.common.annotation.SelectDataScope;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class SelectAndAddAspect {

    //全部数据权限
    public static final String DATA_SCOPE_ALL = "1";

    //自定数据权限
    public static final String DATA_SCOPE_CUSTOM = "2";

    //部门数据权限
    public static final String DATA_SCOPE_DEPT = "3";

    //部门及以下数据权限
    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

    //仅本人数据权限
    public static final String DATA_SCOPE_SELF = "5";

    //数据权限过滤关键字
    public static final String DATA_SCOPE = "dataScope";

    //异常消息
    public static final String EXCEPTION_MESSAGE = "数据过滤未获得权限，请先进行用户登录!";

    public static final String NO_DEPT_EXCEPTION_MESSAGE = "数据添加失败,当前用户不属于任何部门";

    //定义数据过滤查询的切面
    @Pointcut("@annotation(com.ruoyi.common.annotation.SelectDataScope)")
    public void selectPonitCut() {
    }

    //定义默认添加deptID，和userID的切面
    @Pointcut("@annotation(com.ruoyi.common.annotation.AddDataScope)")
    public void addPonitCut() {
    }

    @Before("selectPonitCut()")
    public void doBeforeSelect(JoinPoint point) throws Throwable {
        selectHandleDataScope(point);
    }

    @Before("addPonitCut()")
    public void doBeforeAdd(JoinPoint point) throws Throwable {
        addHandleDataScope(point);
    }

    /**
     * 查询数据过滤具体逻辑
     *
     * @param joinPoint 参数列表
     */
    protected void selectHandleDataScope(final JoinPoint joinPoint) {
        // 获得注解
        SelectDataScope selectDataScope = getSelectAnnotation(joinPoint);
        if (selectDataScope == null) {
            return;
        }
        String alias = selectDataScope.alias(); //表别名

        // 获取当前的用户信息
        SysUser sysUser = getSysUser();
        if (sysUser == null) {
            throw new CustomException(EXCEPTION_MESSAGE);
        }
        // 如果是超级管理员，则不过滤数据
        if (sysUser.isAdmin()) {
            return;
        }

        //遍历当前用户所有角色
        StringBuffer sqlString = new StringBuffer();
        for (SysRole role : sysUser.getRoles()) {
            String dataScope = role.getDataScope(); //获取该角色的数据权限

            if (DATA_SCOPE_ALL.equals(dataScope)) {//全部数据权限
                break;
            } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) { //自定数据权限
                sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", alias, role.getRoleId()));
            } else if (DATA_SCOPE_DEPT.equals(dataScope)) { //部门数据权限
                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", alias, sysUser.getDeptId()));
            } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) { //部门及以下数据权限
                sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                        alias, sysUser.getDeptId(), sysUser.getDeptId()));
            } else if (DATA_SCOPE_SELF.equals(dataScope)) { //仅本人数据权限
                if (StringUtils.isNotBlank(alias)) {
                    sqlString.append(StringUtils.format(" OR {}.user_id = {}", alias, sysUser.getUserId()));
                } else {
                    sqlString.append(" OR 1=0");
                }
            }
        }

        if (StringUtils.isBlank(sqlString.toString())) {
            return;
        }

        //获取第一个参数
        Object params = joinPoint.getArgs()[0];
        //该参数是否是BaseEntity或是BaseEntity的子类
        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
        }
    }

    //添加d添加deptID，和userID 的具体逻辑
    protected void addHandleDataScope(final JoinPoint joinPoint) {
        // 获得注解
        AddDataScope addDataScope = getAddAnnotation(joinPoint);
        if (addDataScope == null) {
            return;
        }

        // 获取当前的用户信息
        SysUser sysUser = getSysUser();
        if (sysUser == null) {
            throw new CustomException(EXCEPTION_MESSAGE);
        }

        //获取第一个参数
        Object params = joinPoint.getArgs()[0];
        if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity) params;
            baseEntity.setScopeUserId(sysUser.getUserId()); //设置当前用户id
            if(sysUser.getDeptId() == null ) {
                throw new CustomException(NO_DEPT_EXCEPTION_MESSAGE);
            }
            baseEntity.setScopeDeptId(sysUser.getDeptId()); //设置当前用户所属的部门id
        }
    }

    /**
     * 是否存在注解，如果存在就获取
     */
    private SelectDataScope getSelectAnnotation(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(SelectDataScope.class);
        }
        return null;
    }

    private AddDataScope getAddAnnotation(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(AddDataScope.class);
        }
        return null;
    }

    /**
     * 获取当前用户
     */
    private SysUser getSysUser() {
        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
        if (StringUtils.isNotNull(loginUser)) {
            SysUser currentUser = loginUser.getUser();
            if (StringUtils.isNotNull(currentUser)) {
                return currentUser;
            }
        }
        return null;
    }
}
